/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package BookTrading;

import jade.core.Agent;
import jade.core.AID;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.UnreadableException;
import java.io.IOException;
import java.util.Hashtable;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class BookEncheresAgent extends Agent {

    // The title of the book to buy
    private String targetBookTitle;
    // The list of known seller agents
    private AID[] sellerAgents;
    // The list of known buyer agents
    private AID[] buyerAgents;

    private Hashtable catalogue_encheres;
    private BookEncheresGUI myGui1;
    private BookObject bookobject;

    // Put agent initializations here
    protected void setup() {
        // Printout a welcome message
        System.out.println("Bienvenue! Dans Jade Commerce " + getAID().getName() + ".");
        // Create the catalogue des enchères crée
        catalogue_encheres = new Hashtable();
        //Creator: NGUYEN Trang
        //Date: 26/02/2015
        // Register the enchere service in the yellow pages
        DFAgentDescription dfd = new DFAgentDescription();
        dfd.setName(getAID());
        ServiceDescription sd = new ServiceDescription();
        sd.setType("object-enchere");
        sd.setName("JADE-enchere");
        dfd.addServices(sd);
        try {
            DFService.register(this, dfd);
        } catch (FIPAException fe) {
            fe.printStackTrace();
        }
        
        addBehaviour(new ReceiveObjectFromSeller());
        
        // Add a TickerBehaviour that schedules a request to seller agents every minute
        addBehaviour(new TickerBehaviour(this, 60000) {
                @Override
                protected void onTick() {
                        System.out.println("Trying to connect to buyer agent... ");
                        // Update the list of seller agents
                        DFAgentDescription template = new DFAgentDescription();
                        ServiceDescription sd = new ServiceDescription();
                        sd.setType("book-buyer");
                        template.addServices(sd);
                        try {
                                DFAgentDescription[] result = DFService.search(myAgent, template); 
                                System.out.println("Found the following seller agents:");
                                buyerAgents = new AID[result.length];
                                for (int i = 0; i < result.length; ++i) {
                                        buyerAgents[i] = result[i].getName();
                                        System.out.println(buyerAgents[i].getName());
                                }
                        }
                        catch (FIPAException fe) {
                                fe.printStackTrace();
                        }

                        // Perform the request
                        myAgent.addBehaviour(new ProcessEnchere());
                }
        } );
        //addBehaviour(new ProcessEnchere());
    }

    // Put agent clean-up operations here
    protected void takeDown() {
        // Printout a dismissal message
        System.out.println("Encheres-agent " + getAID().getName() + " terminating.");
    }

    /**
     * This is invoked by the GUI when the user adds a new book for sale
     *
     * @param nbr_seller_cat
     * @param nbr_buyer_cat
     */
    /*public void updateCatalogue(final int nbr_seller_cat, final int nbr_buyer_cat) {
     addBehaviour(new OneShotBehaviour() {
     public void action() {
     catalogue_encheres.put(new Integer(nbr_seller_cat), new Integer(nbr_buyer_cat));
     System.out.println("Nombre de vendeur(s) : "+nbr_seller_cat+" Nombre d'acheteur(s) "+nbr_buyer_cat);
                        
     }
     } );
     }*/
    //Class Behaviour to receive Object from seller agent
    //Author: NGUYEN TRANG
    //Create date: 27/02/2015
    private class ReceiveObjectFromSeller extends Behaviour {

        boolean result = false;

        @Override
        public void action() {
            ACLMessage msg = receive();
            if (msg != null) {
                bookobject = new BookObject();
                try {
                    bookobject = (BookObject) msg.getContentObject();
                } catch (UnreadableException ex) {
                    Logger.getLogger(BookEncheresAgent.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.println(" Recive object from seller:" + bookobject.getName() + " " + bookobject.getPrice());
                result = true;
            }
        }

        @Override
        public boolean done() {
            return result;
        }
    }

    //Class Behaviour to get list BuyerAgent
    //Author: NGUYEN TRANG
    //Create date: 27/02/2015
    private class ProcessEnchere extends Behaviour {

        private boolean result = false;
        private int step = 0;
        private MessageTemplate mt; // The template to receive replies

        @Override
        public void action() {
            switch (step) {
//                case 0:
//                    // Get the list of buyers agents
//                    DFAgentDescription template = new DFAgentDescription();
//                    ServiceDescription sd = new ServiceDescription();
//                    sd.setType("book-buyer");
//                    template.addServices(sd);
//                    try {
//                        DFAgentDescription[] result = DFService.search(myAgent, template);
//                        System.out.println("Found the following seller agents:");
//                        buyerAgents = new AID[result.length];
//                        for (int i = 0; i < result.length; ++i) {
//                            buyerAgents[i] = result[i].getName();
//                        }
//                        step = 1;
//                    } catch (FIPAException fe) {
//                        fe.printStackTrace();
//                    }
                case 0:
                    // Send the cfp to all buyers
                    ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
                    for (int i = 0; i < buyerAgents.length; ++i) {
                        cfp.addReceiver(buyerAgents[i]);
                    }
                    try {
                        cfp.setContentObject(bookobject);
                       
                    } catch (IOException ex) {
                        Logger.getLogger(BookEncheresAgent.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    cfp.setConversationId("enchere-object");
                    cfp.setReplyWith("cfp" + System.currentTimeMillis()); // Unique value
                    myAgent.send(cfp);
                    // Prepare the template to get proposals
                    mt = MessageTemplate.and(MessageTemplate.MatchConversationId("enchere-object"),
                            MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
                    step = 1;
                    break;
            }
        }

        @Override
        public boolean done() {
            return (step == 1);
        }
    }

    //Get list seller annd buyer
    public void get_list_seller_buyer() {
        addBehaviour(new OneShotBehaviour() {
            public void action() {
                // Update the list of seller agents
                DFAgentDescription template = new DFAgentDescription();
                ServiceDescription sd = new ServiceDescription();
                sd.setType("book-selling");
                template.addServices(sd);

                // Update the list of buyer agents
                DFAgentDescription template_buyer = new DFAgentDescription();
                ServiceDescription sd_buyer = new ServiceDescription();
                sd_buyer.setType("book-buying");
                template_buyer.addServices(sd_buyer);

                try {

                    /*
                     On va crée ujne fonction pour founrir des agents
                     */
                    DFAgentDescription[] result = DFService.search(myAgent, template);
                    //System.out.println("Found the following seller agents:");
                    sellerAgents = new AID[result.length];
                    //sellerAgents[0] = result[0].getName();

                    DFAgentDescription[] result_buyer = DFService.search(myAgent, template_buyer);
                    //System.out.println("Found the following buyer agents:");
                    buyerAgents = new AID[result_buyer.length];
                                                //sellerAgents[0] = result[0].getName();

                    //ici onbtient des list seller, buyer
                    System.out.println("Liste des seller agent :" + result.length);

                    for (int i = 0; i < result.length; ++i) {
                        sellerAgents[i] = result[i].getName();
                        System.out.println(sellerAgents[i].getName());
                        //
                    }

                    System.out.println("Liste des buyer agent :" + result_buyer.length);
                    for (int j = 0; j < result_buyer.length; ++j) {
                        buyerAgents[j] = result_buyer[j].getName();
                        System.out.println(buyerAgents[j].getName());

                    }
                } catch (FIPAException fe) {
                    fe.printStackTrace();
                }

                // Perform the request
                //Ici on peux interagir avec les vendeurs
                //myAgent.addBehaviour(new RequestPerformer());
            }
        });
    }

    public void create_encheres(final String nom_enchere, final int nbr_seller_cat, final int nbr_buyer_cat, final int type_enchere) {
        addBehaviour(new OneShotBehaviour() {
            public void action() {
                //il faudra overide toString pour afficher une enchere crée
                System.out.println("Début de : Création de l'enchère : idEncheres \n ");

                //crée des sellers
                for (int i = 0; i < nbr_seller_cat; i++) {
                    BookSellerAgent atemp = new BookSellerAgent();
//            BookSellerGui aGUi = new BookSellerGui(atemp);
//            System.out.println("Votre nom "+atemp.getLocalName());
//            aGUi.showGui();
                    atemp.setup();
                    //showcataloguefromseller(atemp);
                }

                //crée des buyer
                for (int i = 0; i < nbr_buyer_cat; i++) {
                    BookBuyerAgent atemp = new BookBuyerAgent();
                    //BookBuyerGui aGUi = new BookBuyerGui(atemp, new BookObject("Test",0));
                    //aGUi.showGui();
                    //atemp.showCatalogue();

                }

                System.out.println("L'enchère " + nom_enchere
                        + " comporte " + nbr_seller_cat
                        + " vendeur(s) et "
                        + nbr_buyer_cat + " acheteur(s) \n");

                System.out.println("FIn de : Création de l'enchère : idEncheres \n ");
                get_list_seller_buyer();
            }
        });
    }

    /*
     Inner class RequestPerformer.
     This is the behaviour used by Book-Encheres agents to request seller,buyer 
     agents the target book.
     */
    /*private class RequestPerformer extends Behaviour {
     private AID bestSeller; // The agent who provides the best offer 
     private int bestPrice;  // The best offered price
     private int repliesCnt = 0; // The counter of replies from seller agents
     private MessageTemplate mt; // The template to receive replies
     private int step = 0;

     public void action() {
     switch (step) {
     case 0:
     // Send the cfp to all sellers
     ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
     for (int i = 0; i < sellerAgents.length; ++i) {
     cfp.addReceiver(sellerAgents[i]);
     } 
     cfp.setContent(targetBookTitle);
     cfp.setConversationId("book-trade");
     cfp.setReplyWith("cfp"+System.currentTimeMillis()); // Unique value
     myAgent.send(cfp);
     // Prepare the template to get proposals
     mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"),
     MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
     step = 1;
     break;
     case 1:
     // Receive all proposals/refusals from seller agents
     ACLMessage reply = myAgent.receive(mt);
     if (reply != null) {
     // Reply received
     if (reply.getPerformative() == ACLMessage.PROPOSE) {
     // This is an offer 
     int price = Integer.parseInt(reply.getContent());
     if (bestSeller == null || price < bestPrice) {
     // This is the best offer at present
     bestPrice = price;
     bestSeller = reply.getSender();
     }
     }
     repliesCnt++;
     if (repliesCnt >= sellerAgents.length) {
     // We received all replies
     step = 2; 
     }
     }
     else {
     block();
     }
     break;
     case 2:
     // Send the purchase order to the seller that provided the best offer
     ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
     order.addReceiver(bestSeller);
     order.setContent(targetBookTitle);
     order.setConversationId("book-trade");
     order.setReplyWith("order"+System.currentTimeMillis());
     myAgent.send(order);
     // Prepare the template to get the purchase order reply
     mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"),
     MessageTemplate.MatchInReplyTo(order.getReplyWith()));
     step = 3;
     break;
     case 3:      
     // Receive the purchase order reply
     reply = myAgent.receive(mt);
     if (reply != null) {
     // Purchase order reply received
     if (reply.getPerformative() == ACLMessage.INFORM) {
     // Purchase successful. We can terminate
     System.out.println(targetBookTitle+" successfully purchased from agent "+reply.getSender().getName());
     System.out.println("Price = "+bestPrice);
     myAgent.doDelete();
     }
     else {
     System.out.println("Attempt failed: requested book already sold.");
     }

     step = 4;
     }
     else {
     block();
     }
     break;
     }        
     }

     public boolean done() {
     if (step == 2 && bestSeller == null) {
     System.out.println("Attempt failed: "+targetBookTitle+" not available for sale");
     }
     return ((step == 2 && bestSeller == null) || step == 4);
     }
     }  // End of inner class RequestPerformer*/
}
